/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.soa.controller.wx;

import com.lianzt.commondata.AbstractCommonData;
import com.lianzt.commondata.DataConvertFactory;
import com.lianzt.exception.InstanceDataException;
import com.lianzt.util.HttpConnect;
import com.lianzt.util.StringUtil;
import com.soa.exception.GlobalException;
import com.soa.service.BaseService;
import static com.soa.service.BaseService.getSession;
import com.soa.service.impl.UtilService;
import com.soa.util.AjaxUtil;
import com.soa.util.SystemUtil;
import com.soa.util.wx.TrffUtil;
import com.soa.util.wx.SHA1;
import com.soa.util.wx.WeixinUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 微信相关控制器
 *
 * @author zuotai
 */
@Controller
public class WeixinController {

    @Resource
    private TrffUtil trffUtil;
    @Resource
    private UtilService utilServiceImpl;
    @Resource
    private WeixinUtil weixinUtil;
    private final Logger log = LoggerFactory.getLogger(WeixinController.class);
    private final String WX_ERROR_VIEW = "/wx_error";
    private final String TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

    @RequestMapping(value = "/wx/check", method = RequestMethod.GET)
    public void checkToken(HttpServletRequest request, PrintWriter out) {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        String token = SystemUtil.getSysConfig("wx_token");
        log.info("参数--signature:" + signature + ",timestamp:" + timestamp + ",nonce:" + nonce + ",echostr:" + echostr);
        
        log.debug("===================================================check====================================");
        if (StringUtil.isNull(signature)|| StringUtil.isNull(timestamp)|| StringUtil.isNull(nonce)|| StringUtil.isNull(echostr)) {
            log.error("微信参数为空");
        } else {
            String[] array = new String[]{
                timestamp, nonce, token
            };
            Arrays.sort(array);
            String signTemp = "";
            for (String str : array) {
                signTemp += str;
            }
            signTemp = new SHA1().getDigestOfString(signTemp.getBytes());
            if (signTemp.toLowerCase().equals(signature.toLowerCase())) {
                out.write(echostr);
                log.info("微信签名比对成功");
            } else {
                log.info("微信签名比对失败,生成签名-->" + signTemp);
            }
        }
    }

    /**
     * 接收微信推送
     *
     * @param req
     * @param out
     */
    @RequestMapping(value = "/wx/check", method = RequestMethod.POST)
    public void recvJtgzfwWx(HttpServletRequest request, PrintWriter out) {
        log.debug("接收到微信消息。");
        int contentLength = request.getContentLength();
        InputStream in = null;
        StringBuilder xml = new StringBuilder();
        AbstractCommonData wxData = null;
        AbstractCommonData req = null;
        AbstractCommonData reqHead = null;
        AbstractCommonData res = null;
        AbstractCommonData resHead = null;
        try {
            try {
                in = request.getInputStream();
                byte[] bt = new byte[1024];
                int i = 0, totle = 0;
                while (totle < contentLength) {
                    i = in.read(bt);
                    xml.append(new String(bt, 0, i, "utf-8"));
                    totle += i;
                }
                log.info("接受到微信数据---->{}", xml);
                wxData = weixinUtil.xml2Data(xml.toString());
            } finally {
                try {
                    in.close();
                } catch (IOException ex1) {
                    log.error("关闭数据流错误", ex1);
                }
            }
            req = (AbstractCommonData) request.getAttribute("page_data");
            req.putAll(wxData);
            reqHead = req.getDataValue("head");
            reqHead.putStringValue("service_code", "P40104");
            reqHead.putDateValue("send_time", new Date());
            res = DataConvertFactory.getInstance();     //响应报文
            resHead = res.getDataValue("head");
            BaseService.runService(req, reqHead, res, resHead);
        } catch (GlobalException ge) {
            if (ge.getErrorCode() > 900000) {
                log.warn("系统异常：" + ge);
                log.debug("系统异常: ", ge);
                utilServiceImpl.saveError(ge);
            } else {
                log.warn("error warn:" + ge);
            }
            res = SystemUtil.creatErrorCommonData(ge);
        } catch (DataAccessException e) {
            log.warn("数据库异常：" + e);
            log.debug("数据库异常: ", e);
            res = SystemUtil.creatErrorCommonData(new GlobalException(999998));
            utilServiceImpl.saveError(e);
        } catch (IOException ex) {
            log.error("微信接口接收POST数据错误", ex);
            res = SystemUtil.creatErrorCommonData(new GlobalException(300009));     //微信消息解析异常
        } catch (DocumentException e) {
            log.error("微信消息解析异常:", e);
            res = SystemUtil.creatErrorCommonData(new GlobalException(300009));     //微信消息解析异常
        } catch (Exception e) {
            log.warn("系统未知异常：" + e);
            log.debug("系统未知异常: ", e);
            res = SystemUtil.creatErrorCommonData(new GlobalException(999999));
            utilServiceImpl.saveError(e);
        } finally {
            //暂时不需要返回数据
            if (res != null) {
//                AjaxUtil.sendJsonData(out, res);
            } else {
                log.error("响应报文为空！");
            }
        }
    }

    /**
     * 微信 auth2.0 授权接收，跳转的url中要包含service参数，根据该参数执行服务。
     *
     * @param map
     * @return
     */
    @RequestMapping(value = "/wx/snsapi", method = RequestMethod.GET)
    public String snsapiBaseUrl(HttpServletRequest request, Map map) {
        AbstractCommonData req = (AbstractCommonData) request.getAttribute("page_data");
        AbstractCommonData ses = BaseService.getSession(req);
        ses.putStringValue("openid", request.getParameter("openid"));       //test code
    log.debug("===================================================第一次====================================");
        //session为空时表示第一次进入，只有第一次进入时才获取
        if (StringUtil.isNull(ses.getStringValue("openid"))) {
            //数据校验
            if (StringUtil.isNull(req.getStringValue("code")) || StringUtil.isNull(req.getStringValue("service"))) {       //错误
                map.put("errMsg", "参数错误，请稍候重试！");
                return WX_ERROR_VIEW;
            }
            if (!"lianzt".equals(req.getStringValue("state"))) {       //错误
                map.put("errMsg", "参数错误，请稍候重试！");
                return WX_ERROR_VIEW;
            }
    
            //获取微信用户openid
            String url = String.format(TOKEN_URL, SystemUtil.getSysConfig("wx_appid"), SystemUtil.getSysConfig("wx_appsecret"), req.getStringValue("code"));
            log.debug("请求url：{}", url);
            HttpConnect hc = null;
            AbstractCommonData wxResJson = null;
            String openId = null;
            try {
                hc = new HttpConnect(url);
                String str = hc.receMsg();
                log.debug("收到报文：{}", str);
                wxResJson = DataConvertFactory.getInstanceByJson(str);
                openId = wxResJson.getStringValue("openid");
                log.debug("转为data：{}", wxResJson);
                if (StringUtil.isNull(openId)) {
                    log.error("获取用户id为空！");
                    map.put("errMsg", "获取用户id为空！");
                    return WX_ERROR_VIEW;
                }
            } catch (IOException e) {
                log.error("请求openid异常：", e);
                map.put("errMsg", "获取用户id错误！");
                return WX_ERROR_VIEW;
            } catch (InstanceDataException e) {
                log.error("微信返回id格式异常：", e);
                map.put("errMsg", "数据格式错误！");
                return WX_ERROR_VIEW;
            } finally {
                if (hc != null) {
                    hc.closeStream();
                }
            }
            ses.putStringValue("openid", openId);
        }
        try {
            AbstractCommonData res = BaseService.runService(req, req.getStringValue("service"));        //执行服务
            //服务需要返回一个 view 参数，做为跳转到的视图，其它返回值都放入到 map 中，可在jsp中使用
            map.putAll(res);
            map.put("out_json", DataConvertFactory.praseNormJson(res));

            //增加jsapi初始化的授权码,需要注意url需要严格一致,?号之后的参数也必须一致
            String signUrl = "snsapi.do";
            if (StringUtil.notNull(request.getQueryString())) {
                signUrl += "?" + request.getQueryString();
            }
            //map.put("jsapi", DataConvertFactory.praseNormJson(weixinUtil.getJsapiSign(signUrl)));
            return res.getStringValue("view");
        } catch (GlobalException ge) {
            if (ge.getErrorCode() > 900000) {
                log.warn("系统异常：" + ge);
                utilServiceImpl.saveError(ge);
            }
            map.put("errMsg", ge.getErrorMsg());
            return WX_ERROR_VIEW;
        }
    }

    /**
     * 接收微信浏览器中的post请求，返回一个视图
     *
     * @param request
     * @param map
     * @return
     */
    @RequestMapping(value = "/wx/submit")
    public String submitWx(HttpServletRequest request, Map map) {
        AbstractCommonData req = (AbstractCommonData) request.getAttribute("page_data");
        trffUtil.checkWxLogin(req);      //校验微信登录
        if (StringUtil.isNull(req.getStringValue("service"))) {       //错误
            map.put("errMsg", "参数错误，请稍候重试！");
            return WX_ERROR_VIEW;
        }
        if (StringUtil.isNull(BaseService.getSession(req).getStringValue("openid"))) {
            map.put("errMsg", "参数错误，请稍候重试！");
            return WX_ERROR_VIEW;
        }
        try {
            AbstractCommonData res = BaseService.runService(req, req.getStringValue("service"));        //执行服务
            //服务需要返回一个 view 参数，做为跳转到的视图，其它返回值都放入到 map 中，可在jsp中使用
            if (StringUtil.notNull(res.getStringValue("view"))) {
                map.putAll(res);
                return res.getStringValue("view");
            } else {
                map.put("errMsg", "view为空");
                return WX_ERROR_VIEW;
            }
        } catch (GlobalException ge) {
            if (ge.getErrorCode() > 900000) {
                log.warn("系统异常：" + ge);
                utilServiceImpl.saveError(ge);
            } else {
                //业务级异常，弹出提示后后退
                map.put("_history", true);
            }
            map.put("errMsg", ge.getErrorMsg());
            return WX_ERROR_VIEW;
        }
    }

    /**
     *
     * @param request
     * @param out
     */
    @RequestMapping(value = "/ajax_wx", method = RequestMethod.POST)
    public void ajaxWx(HttpServletRequest request, PrintWriter out) {
        if (log.isDebugEnabled()) {
            log.debug("开始处理ajax请求。");
        }
        AbstractCommonData req = null;
        AbstractCommonData reqHead = null;
        AbstractCommonData res = null;
        AbstractCommonData resHead = null;
        try {
            req = (AbstractCommonData) request.getAttribute("page_data");
            trffUtil.checkWxLogin(req);      //校验微信登录
            reqHead = req.getDataValue("head");

            //校验服务码
            if (StringUtil.isNull(reqHead.getStringValue("service_code"))) {
                throw new GlobalException(999992);      //服务码为空
            }
            reqHead.putDateValue("send_time", new Date());
            res = DataConvertFactory.getInstance();     //响应报文
            resHead = res.getDataValue("head");

            if (StringUtil.isNull(BaseService.getSession(req).getStringValue("openid"))) {
                throw new GlobalException(400105);        //参数错误，请稍候重试！
            }

            BaseService.runService(req, reqHead, res, resHead);
        } catch (GlobalException ge) {
            if (ge.getErrorCode() > 900000) {
                log.warn("系统异常：" + ge);
                log.debug("系统异常: ", ge);
                utilServiceImpl.saveError(ge);
            } else {
                log.warn("error warn:" + ge);
            }
            res = SystemUtil.creatErrorCommonData(ge);
        } catch (DataAccessException e) {
            log.warn("数据库异常：" + e);
            log.debug("数据库异常: ", e);
            res = SystemUtil.creatErrorCommonData(new GlobalException(999998));
            utilServiceImpl.saveError(e);
        } catch (Exception e) {
            log.warn("系统未知异常：" + e);
            log.debug("系统未知异常: ", e);
            res = SystemUtil.creatErrorCommonData(new GlobalException(999999));
            utilServiceImpl.saveError(e);
        } finally {
            if (res != null) {
                AjaxUtil.sendJsonData(out, res);
            } else {
                log.error("响应报文为空！");
            }
        }
    }

    /**
     * 接收微信支付目录下的页面get跳转
     *
     * @param request
     * @param map
     * @param pageName
     * @return
     */
    @RequestMapping(value = "/wx/_page/{pageName}")
    public String getPayPage(HttpServletRequest request, Map map, @PathVariable("pageName") String pageName) {
        if (log.isInfoEnabled()) {
            log.info("请求的页面是：" + pageName);
        }
        AbstractCommonData req = (AbstractCommonData) request.getAttribute("page_data");
        //如果服务码不为空就执行
        if (StringUtil.notNull(req.getDataValue("head").getStringValue("service_code"))) {
            //服务码不为空时执行服务，否则直接返回页面
            try {
                trffUtil.checkWxLogin(req);      //校验微信登录
                AbstractCommonData out = DataConvertFactory.getInstance();
                BaseService.runService(req, req.getDataValue("head"), out, out.getDataValue("head"));

                if (log.isInfoEnabled()) {
                    log.info("响应数据：" + out);
                }
                map.put("out_json", DataConvertFactory.praseNormJson(out));
                map.putAll(out);
            } catch (GlobalException ge) {
                if (ge.getErrorCode() > 900000) {
                    log.warn("系统异常：" + ge);
                    log.debug("系统异常: ", ge);
                    utilServiceImpl.saveError(ge);
                } else {
                    log.warn("error warn:" + ge);
                }
                map.put("errMsg", ge.getErrorMsg());
                return WX_ERROR_VIEW;
            }
        }

        //增加jsapi初始化的授权码,需要注意url需要严格一致,?号之后的参数也必须一致
        String url = "_page/" + pageName + ".do";
        if (StringUtil.notNull(request.getQueryString())) {
            url += "?" + request.getQueryString();
        }
        map.put("jsapi", DataConvertFactory.praseNormJson(weixinUtil.getJsapiSign(url)));

        map.putAll(SystemUtil.tableMap);
        return "/wx/" + pageName;
    }

    /**
     * 接收微信支付目录下的页面get跳转
     *
     * @param request
     * @param map
     * @param pageName
     * @return
     */
    @RequestMapping(value = "/wx/_page/{first}/{second}")
    public String getPayPage(HttpServletRequest request, Map map,
            @PathVariable("first") String first,
            @PathVariable("second") String second) {
        return getPayPage(request, map, first + "/" + second);
    }
}
